{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Maximizing throughput across jobs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import csv\n",
    "cluster_num_gpus=4\n",
    "\n",
    "def get_baseline_perf(job, exec_plan, num_gpus):\n",
    "    baseline_perf = 0\n",
    "    job_trace = \"../../simulator/traces/\" + job + \"/placements.csv\"\n",
    "    with open(job_trace, \"r\", encoding=\"utf-8-sig\") as data:\n",
    "        reader_config = csv.DictReader(data)\n",
    "        data_rows = list(reader_config)\n",
    "    for data_row in data_rows:\n",
    "        if (\n",
    "            data_row[\"placement\"] == str(num_gpus)\n",
    "            and data_row[\"exec_plan\"] == exec_plan\n",
    "        ):\n",
    "            baseline_perf = data_row[\"iter_time\"]\n",
    "    return float(baseline_perf)\n",
    "\n",
    "jobs = [\"roberta\",\"t5_3B\"]\n",
    "\n",
    "scheduler_norm_tpt = {}\n",
    "for job in jobs:\n",
    "    scheduler_norm_tpt.setdefault(job, {})\n",
    "\n",
    "scheduler_norm_tpt[\"roberta\"][\"baseline\"] = get_baseline_perf(\"roberta\", \"ga\", cluster_num_gpus)\n",
    "scheduler_norm_tpt[\"t5_3B\"][\"baseline\"] = get_baseline_perf(\"t5_3B\", \"tp+ga\", cluster_num_gpus)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simple Scheduler Allocation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Simple Scheduler: allocates 2 GPUs to each job.\n",
      "roberta takes 0.697693418 seconds under zero-dp.\n",
      "The normalized throughput of roberta is 0.53.\n",
      "t5_3B takes 3.2757 seconds under zero-offload.\n",
      "The normalized throughput of t5_3B is 0.25.\n"
     ]
    }
   ],
   "source": [
    "from simple_scheduler import SimpleScheduler\n",
    "\n",
    "simple_scheduler = SimpleScheduler(cluster_num_gpus)\n",
    "simple_scheduler.submit(\"roberta\")\n",
    "simple_scheduler.submit(\"t5_3B\")\n",
    "simple_scheduler.allocate()\n",
    "job_performance = simple_scheduler.simulate()\n",
    "print('Simple Scheduler: allocates 2 GPUs to each job.')\n",
    "for job in job_performance:\n",
    "    print(f'{job} takes {job_performance[job][0]} seconds under {job_performance[job][1]}.')\n",
    "    scheduler_norm_tpt[job][\"Simple\"]=round(scheduler_norm_tpt[job][\"baseline\"]/job_performance[job][0],2)\n",
    "    print(f'The normalized throughput of {job} is {scheduler_norm_tpt[job][\"Simple\"]}.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Morphling Scheduler Reconfiguration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Morphling Scheduler: maximizes throughput considering jobs’ resource sensitivity.\n",
      "Reconfiguration result:\n",
      "  allocates 1 GPUs to roberta, and reconfigures it to use zero-dp+ga.\n",
      "  allocates 3 GPUs to t5_3B, and reconfigures it to use tp+ga.\n",
      "roberta takes 0.68361435 seconds under zero-dp.\n",
      "The normalized throughput of roberta is 0.55.\n",
      "t5_3B takes 0.9301 seconds under tp+ga.\n",
      "The normalized throughput of t5_3B is 0.89.\n"
     ]
    }
   ],
   "source": [
    "from Morphling_scheuler import MorphlingScheduler\n",
    "morphling_scheduler = MorphlingScheduler(cluster_num_gpus)\n",
    "morphling_scheduler.submit(\"roberta\")\n",
    "morphling_scheduler.submit(\"t5_3B\")\n",
    "print('Morphling Scheduler: maximizes throughput considering jobs’ resource sensitivity.')\n",
    "allocation = morphling_scheduler.allocate()\n",
    "print(f'Reconfiguration result:')\n",
    "for job in jobs:\n",
    "    print(f'  allocates {allocation[job][0]} GPUs to {job}, and reconfigures it to use {allocation[job][1]}.')\n",
    "\n",
    "job_performance = morphling_scheduler.simulate()\n",
    "for job in job_performance:\n",
    "    print(f'{job} takes {job_performance[job][0]} seconds under {job_performance[job][1]}.')\n",
    "    scheduler_norm_tpt[job][\"Morphling\"]=round(scheduler_norm_tpt[job][\"baseline\"]/job_performance[job][0],2)\n",
    "    print(f'The normalized throughput of {job} is {scheduler_norm_tpt[job][\"Morphling\"]}.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfQAAAChCAYAAAAx4k16AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAA960lEQVR4nO2daXhURdaA35MFkrAGwqJITEA2QRkVFWXYMSCroI6IMDKioJ+ioqLggIKAw+IoyMwo4AKIgqIiLqiDLKI4KKAzKBAWERAQMIQYICxZzvfjdredpNPpTjp9O+l6n+c+oavq1j2dHOrcqjp1jqgqBoPBYDAYyjcRdgtgMBgMBoOh9BiDbjAYDAZDBcAYdIPBYDAYKgDGoBsMBoPBUAEwBt1gMBgMhgqAMegGg8FgMFQAjEE3GAwGg6ECUGqDLiLtRaSPiFQLhEAGg8FgMBj8x2eDLiJPiMi/C5R9CKwFlgPbReTCwIpnMBgMBoPBF/yZod8C/OD8ICK9gZ7AdGAQUAkYH1DpDAaDwWAw+ESUH20vAHa4fe4P/KiqYwFEpDkwNHCiGQwGg8Fg8BV/ZugRgHvg967Ap26f9wP1AiGUwWAwGAwG//DHoP8IXAcgIm2BhoD7nnoD4LfAiWYwGAwGg8FX/FlyfwF4QUS2YBnz/eSfobfDbY/dYDAYDAZD8PB5hq6qc4BhwG5gGdBdVc8CiEgtoA6w2Nf+RORKEXleRL4XkZMickhEPhSRNv59BYPBYDAYDGJXPnQReRtoD7wN/BeIB0YASUAfVV1hi2AGg8FgMJRD/DboIiLAH7AML8Be4L/qZ0cici2wSVXPuZXVBrYBB1X1cr8EMxgMBoMhjPHLoIvIzcAzWEfYAATL8/0gMFpV3yy1QCJvAv1UNaa0fRkMBoPBEC747BQnIoOARVh76I9hnUkXoBkwHHhDRKJU9fVSynQ+cKyUfRgMBoPBEFb4PEMXke3AKaC9qp4uUBcLfAnEqWqLEgsj0h74HHhOVR8uos1wrBcI4uLirkhOTiY6OpqcnBxUlUqVKnHu3DkiIyMREXJycqhUqRLZ2dmF6gFyc3NdZSJCdHQ0586dIyoqClUtVB8VFUV2djZRUVHk5eWRl5fnqo+IiCAyMtJrfUREBDk5OURHR5Obm+uxPjs7m0qVKlWo7+SsN9+pYnyns2fPIiIV6jtVxL9TOH+niIgIcnNzK9R3io6O5rvvvktT1Toe7aMfBv008JiqPl9E/QPA31Q1zqcOC99/HrARyAFaq2qxZ9rbtGmjmzZtKsnjQprMzEyqV69utxgGQ5EYHTWEOhVVR0Vks6p6PA3mT2CZXUCCl/oErOV4vxGRGsAKoCqWh3tYB6g5dOiQ3SIYDF4xOmoIdcJRR/0x6E8C94lIh4IVItIJuBd4wl8BRCQO+BBrL763qn7vbx8VjYQEb+9NBoP9GB01hDrhqKNFOsWJyFwPxQeANY5ocTuwPNybA5diRYm7HnjP14eLSCXgXaAtcIOqfumz5BWYM2fO2C2CweAVo6OGUCccddSbl/udXupaOy53LgFaYQWHKRYRiQTewIoPP0RVP/LlvnDg5MmTdotgMHjF6Kgh1AlHHS3SoKuqP8vxJeEZ4EZgJRAhIoML1C9T1VNlLENIcuGFF9otgsHgFaOjhlAnHHXUn+QsgeYyx8/rHFdBkrGOyYUd+/bto3nz5naLYTAUidFRQ6gTjjrqt0EXkRZALyyDq1ihXz9U1VR/+lHVTv4+O1yIiTFB8gyhjdFRQ6gTjjrqT6Q4AWZhebNLgeppIvIPVX0gkMIFiszMTI4ePUp2drbdovhEXl4e27dvt1sMg6FIQkVHo6KiiImJoU6dOmE5gBuKpmbNmnaLEHT8maE/BNwHLAVmYCVRAbgYeATrSNs+VX02sCKWjszMTI4cOUKDBg2IjY3Fei8JbU6fPk1sbKzdYhgMRRIKOqqq5OTkcPLkSfbv30+9evWoUaOGrTIZQofDhw+HnVH3x6DfibW0fkuB8k3AQBGpghWSNaQM+tGjR2nQoAFxcSUKYGcL0dHRdotgMHglFHTUGQozPj6eypUrc/jwYWPQDS7q1q1rtwhBxx9P9mTgYy/1K/g9pWrIkJ2dbftMwl9yc3PtFsFg8Eqo6WhsbCxnz561WwxDCBGOx9b8MejHAG+JV1oQolnSysMyuzt5eXl2i2AweCXUdLS8/R+vyBw4cICRI0dyzTXXEBcXh4iwd+9ev/v529/+hojwxz/+0Wu7xYsXIyJccMEF+cqzsrL8fmZ5xx+Dvhy4W0TudASFAUBEIkRkGHA3fkSJMxRN5cqV7RbBYPCK0VFDUezevZu33nqL+Ph42rdvX6I+9uzZw5QpU4pdNs/IyGDUqFHUr1+/UF04nkP3x6D/FcsRbg5wREQ2iMgG4AgwD9jqaGMoJWbp0BDqGB01FEWHDh04cuQIK1as4Oabby5RH/fccw+33XYbLVp4z8b96KOP0rp1a7p3716obt++fSV6dnnGZ6c4VT0uIldhOb714vf98k3AB8BLqnou4BKWAfsHDgpYX4lL3ghYX04iIso6SJ9/JCUlcdFFF/HZZ58V21ZEePLJJ5kwYQIAa9eupXPnzqxZs4ZOnTqVraA20u/xJQHra/nTAwPWlycmTJjAxIkT8TV1sidKo6OBeL4hdCnt+PXGG2/w7bffsnjxYgYMGFBku/Xr17No0SK2bNnC5MmTC9WXJ0foQOHXb15Vz6nqP1T1elVt4biuV9V/lRdjHkrMnz8fEUFE+Pjj3/0NncntAfr374+IEBVlZ1A/Q3khNTWV2267jUaNGhETE0P9+vW55pprGDNmTECdhNx11GAIFMePH2fUqFFMnz6dWrVqFdkuOzub4cOHM3r0aC666CKPbapWrVpWYoYsYW0lPM2uz2zdRtrMWSQ8+AAxLS8u8t5AzvJjYmJ47bXXuP766wFLWaOiojh+/DgrVqwgJiam3ATFKUiHDh04ffo0lSpVsluUoFCa2XVpZ/lff/01nTp1om7dutx+++0kJiZy+PBhvv32W5577jnuvvtuqlatyrhx4xgzZkypnuXUUYMhkIwePZqmTZsydOhQr+2mTZvG2bNnGTt2bJFtjh496vWloCLiLX3qK1ihXYeraq7jsy/kAGnAKlVdFQAZg4avxjzQ9O7dm+XLl3Py5EmqVq3qOuP75ptvApCSksJHHwUmGd2pU6eoUqVKQPryhYiICBPBK0hMmjSJmJgYNm7cWMiZKD093bUEGRUVVWpjHArn0A0Viy+++IKFCxfy7bffej21sHv3bqZMmcKyZcu8ji2eHOUqOt6W3LsAnd3aOD8Xd/UAHgT+LSKjy0TqMsAuYw5w6623cu7cOd59913g9zO+r732Gr169SI+Pr7QPa+88gqtW7d2hb0cMmQIBw4cyNdm6NChREVF8fPPPzNgwABq1qzpOgLirDtw4AD9+vWjWrVq1K5dm3vuuafIpdmNGzfSrl07YmNjadiwIc8+W3wMobVr1yIirF27tpBcR44c4U9/+hPVq1cnPj6eO++8k9OnT+e7X1WZMmUKDRs2JDY2lrZt27J+/Xo6depUoffkS8Lu3btp3ry5R8/gWrVquQa/CRMmFBowk5KS6NatGxs2bODaa68lLi6Oiy66iKVLlwLwzTff0L59e+Li4rjwwguZP39+vvud20erVq1i1KhR1KtXjypVqtCzZ092797tk/yrVq2iS5cuVKtWjSpVqtCxY0e++OKLEvwmDOWRESNGMGzYMC644AIyMjLIyMggJyeH3NxcMjIyXI6Y999/P126dKFt27audufOnUNVycjIcI0hGRkZNn4beyjSoKtqkqo2UtVst8/JPlyJQE3gdeD/gvM1Soe/xvzM1m3FtvGHunXrct111/Haa68B1hnfPXv28NVXXzFkyJBC7adOncqwYcOoXr0606dP54477uDtt9+mXbt2pKen52urqnTv3p1KlSoxdepU7rrrrnx1119/PVFRUUybNo1+/frx4osv8qc//anQM/fv30+fPn249tprefbZZ2ncuDEPP/wwn376aYm+s6rSo0cPoqOjmTZtGv379+fll1/mqaeeytfur3/9K+PGjaNFixbMmDGDtm3b0qdPn0IvLwbLKP/vf/9j06ZNJbp/37599O/fn86dOzNt2jSio6MZOHAgb731Fn379qVDhw5Mnz6duLg4hg8fzo4dOwr18fDDD/PFF18wduxYHnzwQdatW0enTp0K6WVB3nrrLVJSUgBrpWHy5MlkZGTQtWtX1q1bV6LvYyhfbN++nRdffJH4+HjXtX79ejZs2EB8fDwvvPACANu2bWPFihX52i1evJhDhw4RHx/vWoY/c+aMnV/HFspkE0xVz4nIW0DLsug/kJTEmKfNnBVwOQYPHsyQIUM4dOgQ9evXZ9GiRcTHx9OrVy+WL1/uapeWlsaECRP44x//yJo1a1xLpx06dKB3795MnTqV6dOnu9rn5eXRrVs3nn/++ULPzMvL4/LLL2fBggWusvPOO4+nn36aTz/9NN9RkF27dvHxxx/To0cPAO644w4SExN56aWXPB4ZKY68vDy6d+/O1KlTAeuYSnp6Oi+99BJ/+9vfAGsP7JlnniElJYWPP/7Y5T17ySWXcOeddxYKJBHujBkzhs8++4yrrrqKyy+/nPbt29OxY0euu+46n7ZZdu/ezcqVK+nWrRsA3bp14+KLL2bgwIF89tlndOnSBYCuXbty8cUX8+qrr7r+fk7OnDnDd99954rO2KlTJ1JSUpgxY4br71qQU6dOcc89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zJmTr+0LL7yggKampvr9nKIANmkRNtGfJfeJwD3AEuAqoIbjutpRNsLRxp+XibOqGn6uiMWwLwyzBBmKp2/fvmzYsIE9e/a4yvbu3cv69evzzRY8Ub9+fY4fP87u3bvzlX/99dcANGjQIF+5iNCkSROaN29OVlYW8+bNY8iQIVStWhUwOmooHrtjuac5VqJKczrEEwsWLKBevXp0797dVebtFAlAXrCO0BVl6QtewCHgHS/17wKHfO3Pw/1mhu7gxx9/tFsEQwhy8uRJbdy4sbZq1Urfe+89Xb58uV566aWanJzsmjmrqu7du1cjIyN14sSJrrKffvpJq1Wrpk2aNNH58+fr6tWrdfr06VqtWjW94oorNDc319V2zJgxunTpUl2zZo3OmzdPmzZtqs2bN9djx4652hgdNRSF+wzdF8piJr/vllt107gnVFW1Xr16Onz48EJt7rnnHk1ISPDpmU5+/vlnjYiI0IceeihfeV5ennbo0EEvvvhi3bhxo544cUK//vprbdGihV5//fV+PaM48DJD92cPvTqw0kv9SoKwBy4iw4HhABdccAGpqamcf/75pKWlce7cOS688EL27dtH9erViYqKIj09nQYNGnDkyBHy8vK44IIL2L9/v+vNKSMjg8TERA4cOEBERAT16tXj4MGD1KpVi5ycHDIzM119VqpUiYSEBA4dOkRCQgJnzpzh5MmTrvqYmBhq1qzJ4cOHqVu3LidPniQrK8tVHxcXR9WqVTl69Cj169cnIyODM2fOuOqrVq1KTEwMJ06cIDMzs0J9p7S0tAr3d7LjO82dO5dnn32WwYMHk5eXR5cuXXjwwQdJS0sjJyeHw4cPc+bMGXJzczl69CinT592fadPPvmESZMm8fjjj3Ps2DHq16/PHXfcwa233sqhQ4dc3+nAgQPMnz+fY8eOUadOHTp37szYsWPJyckhNTWVBg0akJWVxc6dO83fyXynQt/pWHIS56pUoU6jZFJTU71+px83biJv1WoSht/F3sgIzi9m3Ktz+gx7P/mE2D8PoVZyEqmpqR6/02/Nm1E58wSpqamkp6cTHR1Nampqvu9UpUoVjh8/Tlpams9/p7feeou8vDxSUlJIT0/P952ee+45Jk6cyJVXXumyVx07duTVV19lz549Afs7eaUoS1/wAtYA87zUvwSs9rU/D/ebGbqD7du32y2C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",
      "text/plain": [
       "<Figure size 576x144 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "pd.set_option('display.max_colwidth', 1000)\n",
    "pd.set_option('display.max_columns', 100)\n",
    "matplotlib.rcParams.update({\"font.size\": 17,'lines.linewidth': 4.3})\n",
    "\n",
    "plt.figure(figsize=(8,2))\n",
    "\n",
    "# Bar chart configuration\n",
    "size = 3\n",
    "x = np.arange(size)\n",
    "total_width, n = 0.4, 2\n",
    "width = total_width / n\n",
    "x = x - (total_width - width) / 2\n",
    "colors = [\"#E15759\", \"#4E79A7\"]\n",
    "hatchs = [\"//\", \"\\\\\"]\n",
    "\n",
    "i=0\n",
    "text_x=-0.11\n",
    "for scheduler in [\"Morphling\",\"Simple\"]:\n",
    "    norm_tpt = []\n",
    "    for job in scheduler_norm_tpt:\n",
    "        norm_tpt.append(scheduler_norm_tpt[job][scheduler])\n",
    "    norm_tpt.append(sum(norm_tpt))\n",
    "    plt.bar(x, norm_tpt, edgecolor=colors[i],linewidth=2, width=width, label=scheduler,hatch=hatchs[i],fill=False)\n",
    "    for tpt in norm_tpt:\n",
    "        plt.text(text_x,tpt+0.2,tpt,ha='center', va='center',fontsize=16)\n",
    "        text_x+=1\n",
    "    x+=width\n",
    "    i+=1\n",
    "    text_x=0.11\n",
    "    \n",
    "\n",
    "plt.ylabel(\"Speedup of jobs\")\n",
    "plt.legend(loc=\"upper left\",ncol=2,handlelength=1)\n",
    "plt.xticks([0,1,2],[\"RoBERTa\",\"T5\",\"Overall\"])\n",
    "plt.ylim([0,2])\n",
    "plt.grid(linestyle = 'dashed', linewidth = 0.5)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
